#include "IR.h"
#include <any>
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
#include "Diagnostic.h"
#include "SysYIRGenerator.h"
#include "IRBuilder.h"

// #define DEBUG

void debug(const std::string &str)
{
#ifdef DEBUG
    std::cout << "[debug]: " << str << std::endl;
    std::cout.flush();
#endif
}

void debug_value(const sysy::Value *val) {
#ifdef DEBUG
    std::cout << "[debug-value]: ";
    std::cout << val->getName() << ": ";
    val->print(std::cout);
    std::cout << " : ";
    std::cout << *val->getType() << "\n";
    std::cout.flush();
#endif
}
namespace sysy
{

any SysYIRGenerator::visitCompUnit(SysYParser::CompUnitContext *ctx)
{
/*
*/
#ifdef DEBUG
    std::cout << "visitCompUnit" << std::endl;
    cout.flush();
#endif
    auto pCompUnit = new CompUnit();
    assert(pCompUnit);
    compUnit.reset(pCompUnit);
    SymbolTable::ModuleScope scope(compUnit->symbols);
    // visitChildren(ctx);
    for (auto dc : ctx->decl())
        visitDecl(dc);
    for (auto fc : ctx->funcDef())
        visitFuncDef(fc);
    return pCompUnit;
    // cout << '1' <<endl;
    // return 0;   //为什么返回两个
}

any SysYIRGenerator::visitDecl(SysYParser::DeclContext *ctx)
{
#ifdef DEBUG
    std::cout << "visitDecl" << std::endl;
    cout.flush();
#endif
    // There is some problems...
    // return compUnit->symbols.isModuleScope() ? visitConstDecl(ctx) : visitVarDecl(ctx);
    auto *child = ctx->children[0];
    auto *constdecl = dynamic_cast<SysYParser::ConstDeclContext *>(child);
    auto *vardecl = dynamic_cast<SysYParser::VarDeclContext *>(child);
    if (constdecl != nullptr)
    {
        return visitConstDecl(ctx->constDecl());
    }
    else if (vardecl != nullptr)
    {
        return visitVarDecl(ctx->varDecl());
    }
}

any SysYIRGenerator::visitConstDecl(SysYParser::ConstDeclContext *ctx)
{
#ifdef DEBUG
    std::cout << "visitConstDecl" << std::endl;
    std::cout.flush();
#endif
    std::vector<Value *> values;
    Type *constType;
    // if (compUnit->symbols.isModuleScope())
    //     constType = any_cast<Type *>(visitBType(ctx->bType()));
    // else 
        constType = Type::getPointerType(any_cast<Type *>(visitBType(ctx->bType())));
    for (auto constdef : ctx->constDef())
    {
        auto name = constdef->Ident()->getText();
        // debug(constdef->Equal());
        Value *initval;
        if (compUnit->symbols.isModuleScope()) {
            if (constdef->constInitVal()) {
                initval = any_cast<Value *>(visitConstInitVal(constdef->constInitVal()));
                auto store = compUnit->createGlobalValue(name, constType, {}, initval);
                // debug("output store:");
                // debug_value(store);
                values.push_back(store);
                compUnit->symbols.insert(name, store);
            } else {
                auto store = compUnit->createGlobalValue(name, constType, {}, nullptr);
                // debug("output store:");
                // debug_value(store);
                values.push_back(store);
                compUnit->symbols.insert(name, store);
            }
        } else {
            auto alloca = builder.createAllocaInst(constType, {}, name);
            if (constdef->constInitVal()) {
                Value *val = any_cast<Value *>(visitConstInitVal(constdef->constInitVal()));
                auto store = builder.createStoreInst(val, alloca);
            } else {
                if(constType->isInt())
                    auto *store = builder.createStoreInst(ConstantValue::get(0, "0"), alloca);
                else if(constType->isFloat())
                    auto *store = builder.createStoreInst(ConstantValue::get(0.0f, "0.0"), alloca);
            }
            values.push_back(alloca);
#ifdef DEBUG
            std::cout << "debug for var decl: " << alloca->isPointer() << "\n";
#endif
            debug_value(alloca);
            compUnit->symbols.insert(name, alloca);
        }

    }
    return values;
}

any SysYIRGenerator::visitVarDecl(SysYParser::VarDeclContext *ctx)
{
#ifdef DEBUG
    std::cout << "visitVarDecl" << std::endl;
    cout.flush();
#endif
    std::vector<Value *> values;
    Type *varType;
    // if (compUnit->symbols.isModuleScope())
    //     varType = any_cast<Type *>(visitBType(ctx->bType()));
    // else 
        varType = Type::getPointerType(any_cast<Type *>(visitBType(ctx->bType())));
    for (auto vardef : ctx->varDef())
    {
        auto name = vardef->Ident()->getText();
        Value *initval;
        if (compUnit->symbols.isModuleScope()) {
            if (vardef->initVal()) {
                initval = any_cast<Value *>(visitInitVal(vardef->initVal()));
                auto store = compUnit->createGlobalValue(name, varType, {}, initval);
                // debug("output store:");
                // std::cout << *store << "\n";
                // debug_value(store);
                values.push_back(store);
                compUnit->symbols.insert(name, store);
            } else {
                auto store = compUnit->createGlobalValue(name, varType, {}, nullptr);
                // debug("output store:");
                // debug_value(store);
                values.push_back(store);
                compUnit->symbols.insert(name, store);
            }
        } else {
            auto alloca = builder.createAllocaInst(varType, {}, name);
            if (vardef->initVal()) {
                Value *val = any_cast<Value *>(visitInitVal(vardef->initVal()));
                auto store = builder.createStoreInst(val, alloca);
            } 
            else {
                if(varType->isInt())
                    auto *store = builder.createStoreInst(ConstantValue::get(0, "0"), alloca);
                else if(varType->isFloat())
                    auto *store = builder.createStoreInst(ConstantValue::get(0.0f, "0.0"), alloca);
            }
            values.push_back(alloca);
#ifdef DEBUG
            std::cout << "debug for var decl: " << alloca->isPointer() << "\n";
#endif
            // debug_value(alloca);
            compUnit->symbols.insert(name, alloca);
        }
    }
    return values;
}


any SysYIRGenerator::visitVarDef(SysYParser::VarDefContext *ctx) // deprecated
{ // legacied
#ifdef DEBUG
    std::cout << "visitVarDef" << std::endl;
    cout.flush();
#endif
    auto name = ctx->Ident()->getText();
    // auto alloca = builder.createAllocaInst(type, {}, name);
    auto pointer = compUnit->symbols.lookup(name);
    // builder.createStoreInst(val, pointer);
    if (ctx->Equal()->getText() != "")
    {
        Value *val = any_cast<Value *>(visitInitVal(ctx->initVal()));
        compUnit->symbols.insert(name, val);
    }
    else
    {
        compUnit->symbols.insert(name, (Value *)nullptr);
        auto pointer = compUnit->symbols.lookup(name);
        builder.createStoreInst((Value *)(nullptr), pointer);
    }
}

any SysYIRGenerator::visitFuncDef(SysYParser::FuncDefContext *ctx)
{
#ifdef DEBUG
    std::cout << "visitFuncDef" << std::endl;
    cout.flush();
#endif
    auto name = ctx->Ident()->getText();
    vector<Type *> paramTypes;
    vector<string> paramNames;
    if (ctx->funcFParams())
    {
        auto params = ctx->funcFParams()->funcFParam();
        for (auto param : params)
        {
            paramTypes.push_back(any_cast<Type *>(visitBType(param->bType())));
            paramNames.push_back(param->Ident()->getText());
        }
    }
    Type *returnType = any_cast<Type *>(visitFuncType(ctx->funcType()));
    // debug("finished functype");
    cout.flush();
    auto funcType = Type::getFunctionType(returnType, paramTypes);
    auto function = compUnit->createFunction(name, funcType);
    cout.flush();
    compUnit->symbols.insert(name, function);
    // debug("finished compUnit->symbols insert");
    cout.flush();
    SymbolTable::FunctionScope scope(compUnit->symbols);
    auto entry = function->getEntryBlock();
    for (auto i = 0; i < paramTypes.size(); ++i)
    {
        auto arg = entry->createArgument(paramTypes[i], paramNames[i]);
        compUnit->symbols.insert(paramNames[i], arg);
    }
    builder.setPosition(entry, entry->end());

    visitBlock(ctx->block());
    return function;
}

any SysYIRGenerator::visitBType(SysYParser::BTypeContext *ctx)
{
#ifdef DEBUG
    std::cout << "visitBType" << std::endl;
    cout.flush();
#endif
    return ctx->Int() ? Type::getIntType() : Type::getFloatType();
}

any SysYIRGenerator::visitConstDef(SysYParser::ConstDefContext *ctx) // Deprecated
{
    auto name = ctx->Ident()->getText();
    Value *val = any_cast<Value *>(visitConstInitVal(ctx->constInitVal()));
    std::pair<std::string, Value *> returnSymbol(name, val);
    return returnSymbol;
}

any SysYIRGenerator::visitConstInitVal(SysYParser::ConstInitValContext *ctx)
{
    return ctx->constExp() ? visitConstExp(ctx->constExp()) : (Value *)nullptr;
}

// leslie 4.23
any SysYIRGenerator::visitInitVal(SysYParser::InitValContext *ctx)
{
#ifdef DEBUG
    std::cout << "visitInitVal" << std::endl;
    cout.flush();
#endif
    return ctx->exp() ? visitExp(ctx->exp()) : (Value *)nullptr;
}
//

// any SysYIRGenerator::visitConstExp(SysYParser::ConstExpContext *ctx) {
//   return visitAddExp(ctx->addExp());
// }

any SysYIRGenerator::visitFuncType(SysYParser::FuncTypeContext *ctx)
{
#ifdef DEBUG
    std::cout << "visitFuncType" << std::endl;
    cout.flush();
#endif
    return ctx->Int() ? Type::getIntType() : (ctx->Float() ? Type::getFloatType() : Type::getVoidType());
}

// leslie 4.23
any SysYIRGenerator::visitFuncFParam(SysYParser::FuncFParamContext *ctx) // deprecated
{
    Type *valType = any_cast<Type *>(visitBType(ctx->bType()));
    return ctx->Ident()->getText();
}

any SysYIRGenerator::visitFuncFParams(SysYParser::FuncFParamsContext *ctx) // deprecated
{
    vector<string> fparamNames;
    for (auto fp : ctx->funcFParam())
    {
        // fparamNames.push_back(fp->Ident()->getText());
        auto x = visitFuncFParam(fp);
    }
    return fparamNames;
}

any SysYIRGenerator::visitBlock(SysYParser::BlockContext *ctx)
{
#ifdef DEBUG
    std::cout << "visitBlock" << std::endl;
    cout.flush();
#endif
    // auto entry = builder.getBasicBlock();
    SymbolTable::BlockScope scope(compUnit->symbols);
    for (auto item : ctx->blockItem())
    {
        visitBlockItem(item);
    }
    return (Value *)(builder.getBasicBlock());
}

any SysYIRGenerator::visitBlockItem(SysYParser::BlockItemContext *ctx)
{
#ifdef DEBUG
    std::cout << "visitBlockItem" << std::endl;
    cout.flush();
#endif
    // return compUnit->symbols.isModuleScope() || compUnit->symbols.isFunctionScope() || compUnit->symbols.isBlockScope() ?
    //  visitDecl(ctx->decl()) : visitStmt(ctx->stmt());
    auto *child = ctx->children[0];
    auto *decl = dynamic_cast<SysYParser::DeclContext *>(child);
    auto *stmt = dynamic_cast<SysYParser::StmtContext *>(child);
    if (decl != nullptr)
    {
        return visitDecl(ctx->decl());
    }
    else if (stmt != nullptr)
    {
        return visitStmt(ctx->stmt());
    }
}

// any SysYIRGenerator::visitBlockItem(SysYParser::BlockItemContext *ctx) { // TODO
//   return ctx->decl() ? visitDecl(ctx->decl()) : visitStmt(ctx->stmt());
// }

any SysYIRGenerator::visitLVal(SysYParser::LValContext *ctx)
{ // TODO
#ifdef DEBUG
    std::cout << "visitLVal" << std::endl;
    cout.flush();
#endif
    // return ctx->Ident(); // there is some problem...
    auto name = ctx->Ident()->getText();
    Value *val = compUnit->symbols.lookup(name);
    debug("lVal: ");
    debug_value(val);
    if (val == nullptr)
        perror("undefined");
    if (isa<GlobalValue>(val) or isa<AllocaInst>(val))
        val = builder.createLoadInst(val);
    // debug("kaka");
    return val;
}

any SysYIRGenerator::visitPrimaryExp(SysYParser::PrimaryExpContext *ctx)
{ // TODO
#ifdef DEBUG
    std::cout << "visitPrimary" << std::endl;
    cout.flush();
#endif
    auto *child = ctx->children[0];
    auto *left = dynamic_cast<antlr4::tree::TerminalNode *>(child);
    auto *number = dynamic_cast<SysYParser::NumberContext *>(child);
    auto *lval = dynamic_cast<SysYParser::LValContext *>(child);
    if (number != nullptr)
    {
        return any_cast<Value *>(visitNumber(ctx->number()));
    }
    else if (lval != nullptr)
    {
        // debug("primary any cast");
        auto val = any_cast<Value *>(visitLVal(ctx->lVal()));
        debug("primary any cast finished"); 
        // auto valtype = dynamic_cast<PointerType *>(val->getType())->getBaseType();   
#ifdef DEBUG
        // std::cout<<"ValType: "<< valtype <<std::endl;
        // std::cout.flush();
#endif
        // Value *ret = builder.createLoadInst(val, {});
        return val;
    }
    else
    {
        return any_cast<Value *>(visitExp(ctx->exp()));
    }
}

any SysYIRGenerator::visitUnaryExp(SysYParser::UnaryExpContext *ctx)
{ 
#ifdef DEBUG
    std::cout << "visitUnaryExp" << std::endl;
    cout.flush();
#endif
    auto *child = ctx->children[0];
    auto *pry = dynamic_cast<SysYParser::PrimaryExpContext *>(child);
    auto *uryop = dynamic_cast<SysYParser::UnaryOpContext *>(child);
    auto *left = dynamic_cast<antlr4::tree::TerminalNode *>(child);
    if (pry != nullptr)
    {
        auto ret = any_cast<Value *>(visitPrimaryExp(ctx->primaryExp()));
        // debug("unary any cast finished");
        return ret;
    }
    else if (left != nullptr)
    {
        auto *callee = compUnit->getFunction(ctx->Ident()->getText());
        vector<Value *> args;
        if (ctx->funcRParams() != nullptr)
            for (auto param: ctx->funcRParams()->exp()) {
                args.push_back(any_cast<Value *>(visitExp(param)));
            }
        if (callee == nullptr) {
            // 此部分理论是应该报错的，为了测试，保证putint()函数正常，此处直接自动生成一个空函数
            // 仅保证测试
            vector<Type *> paramTypes;
            for (auto arg: args) {
                paramTypes.push_back(arg->getType());
            }
            Type *returnType = Type::getIntType();
            auto funcType = Type::getFunctionType(returnType, paramTypes);
            // create the IR function
            callee = compUnit->createFunction(ctx->Ident()->getText(), funcType);
        }
        auto *entry = callee->getEntryBlock();
        auto *parent = entry->getParent();
        return (Value *)builder.createCallInst(callee, args);
    }
    else if (uryop != nullptr)
    {
        auto Op = ctx->unaryOp()->getText();
        // Value *val = any_cast<Value *>(visitUnaryOp(ctx->unaryOp()));
        // debug("Begin to get exp");
        auto Exp = any_cast<Value *>(visitUnaryExp(ctx->unaryExp()));
        // debug("Success to get exp");
        if (Exp->isInt()) {
            if (ctx->unaryOp()->Add()) {
                auto ret = (Value *)(builder.createPosInst(Exp));
                return ret;
            } else if (ctx->unaryOp()->Minus()) {
                auto ret = (Value *)(builder.createNegInst(Exp));
                return ret;
            } else if (ctx->unaryOp()->ExclamationPoint()) {
                auto ret = (Value *)(builder.createNotInst(Exp));
                return ret;
            }
        } else if (Exp->isFloat()) {
            if (ctx->unaryOp()->Add()) {
                auto ret = (Value *)(builder.createFPosInst(Exp));
                return (Value *)nullptr;
            } else if (ctx->unaryOp()->Minus()) {
                auto ret = (Value *)(builder.createFNegInst(Exp));
                return ret;
            } else if (ctx->unaryOp()->ExclamationPoint()) {
                auto ret = (Value *)(builder.createNotInst(Exp));
                return ret;
            }
        }
        return (Value *)nullptr;
    }
}

// any SysYIRGenerator::visitAssignStmt(SysYParser::AssignStmtContext *ctx) {
//   auto rhs = any_cast<Value *>(ctx->exp()->accept(this));
//   // auto lVal = visitLVal(ctx->lVal());
//   auto name = ctx->lVal()->Ident()->getText();
//   auto pointer = compUnit->symbols.lookup(name);
//   if (!pointer)
//     perror("undefined");
//   Value *store = builder.createStoreInst(rhs, pointer);
//   return store;
// }

any SysYIRGenerator::visitExpStmt(SysYParser::ExpStmtContext *ctx)
{
#ifdef DEBUG
    std::cout << "visitExpStmt" << std::endl;
    cout.flush();
#endif
    return visitExp(ctx->exp());
}

any SysYIRGenerator::visitNumber(SysYParser::NumberContext *ctx)
{
#ifdef DEBUG
    std::cout << "visitNumber" << std::endl;
    cout.flush();
#endif
    Value *result = (Value *)nullptr;
    assert(ctx->IntConst() || ctx->FloatConst());
    if (ctx->IntConst())
        return (Value*)ConstantValue::get(std::stoi(ctx->IntConst()->getText()), ctx->IntConst()->getText());
    else
        return (Value*)ConstantValue::get(std::stof(ctx->FloatConst()->getText()), ctx->FloatConst()->getText());
}

any SysYIRGenerator::visitContinueStmt(SysYParser::ContinueStmtContext *ctx)
{
#ifdef DEBUG
    std::cout << "visitContinueStmt" << std::endl;
    cout.flush();
#endif
    // 获得起始的block
    BasicBlock *lst = circle.getStartBlock();
    // 无条件跳转到lst
    Value *retInst = builder.createUncondBrInst(lst, {});
    return retInst;
}

any SysYIRGenerator::visitBreakStmt(SysYParser::BreakStmtContext *ctx)
{
#ifdef DEBUG
    std::cout << "visitBreakStmt" << std::endl;
    cout.flush();
#endif
    // 获得起始的block
    BasicBlock *lst = circle.getExitBlock();
    // 无条件跳转到lst
    Value *retInst = builder.createUncondBrInst(lst, {});
    return retInst;
}

/*------------------------ylyl----------------------------------------*/

any SysYIRGenerator::visitFuncRParams(SysYParser::FuncRParamsContext *ctx) // Deprecated
{
    vector<Value *> values;
    int length = ctx->exp().size();
    for (int i = 0; i < length; i++)
    {
        auto exp = any_cast<Value *>(visitExp(ctx->exp(i)));
        values.push_back(exp);
    }
}

any SysYIRGenerator::visitMulExp(SysYParser::MulExpContext *ctx)
{
#ifdef DEBUG
    std::cout << "visitMulExp" << std::endl;
    cout.flush();
#endif
    auto child = ctx->children[0];
    auto uE = dynamic_cast<SysYParser::UnaryExpContext *>(child);
    auto mE = dynamic_cast<SysYParser::MulExpContext *>(child);
    string Tn = ""; // the name need to be unitied
    if (uE != NULL)
    {
        auto ret = any_cast<Value *>(visitUnaryExp(ctx->unaryExp()));
        // debug("mulexp anycast finished");
        return ret;
    }
    else if (mE != NULL)
    {
        auto lterm = any_cast<Value *>(visitMulExp(ctx->mulExp()));
        auto rterm = any_cast<Value *>(visitUnaryExp(ctx->unaryExp()));
        if (ctx->Multiply())
        {
            return (Value *)(builder.createMulInst(lterm, rterm, Tn));
        }
        else if (ctx->Divide())
        {
            return (Value *)(builder.createDivInst(lterm, rterm, Tn));
        }
        else if (ctx->Mod())
        {
            return (Value *)(builder.createModInst(lterm, rterm, Tn));
        }
    }
}

any SysYIRGenerator::visitEqExp(SysYParser::EqExpContext *ctx)
{
#ifdef DEBUG
    std::cout << "visitEqExp" << std::endl;
    cout.flush();
#endif
    auto child = ctx->children[0];
    auto rE = dynamic_cast<SysYParser::RelExpContext *>(child);
    auto eE = dynamic_cast<SysYParser::EqExpContext *>(child);
    string Tn = ""; // the name need to be unitied
    if (rE != NULL)
    {
        return visitRelExp(ctx->relExp());
    }
    else if (eE != NULL)
    {
        auto lterm = any_cast<Value *>(visitEqExp(ctx->eqExp()));
        auto rterm = any_cast<Value *>(visitRelExp(ctx->relExp()));
        if (ctx->EqualEqual())
        {
            return (Value *)(builder.createICmpEQInst(lterm, rterm, Tn));
        }
        else if (ctx->NotEqual())
        {
            return (Value *)(builder.createICmpNEInst(lterm, rterm, Tn));
        }
    }
}

/*------------------------ylyl----------------------------------------*/

// cty 4.23
any SysYIRGenerator::visitExp(SysYParser::ExpContext *ctx)
{
#ifdef DEBUG
    std::cout << "visitExp" << std::endl;
    cout.flush();
#endif
    if (!ctx){
        debug("get empty");
        return (Value *)nullptr;
    }
    auto *child = ctx->children[0];
    auto *addexp = dynamic_cast<SysYParser::AddExpContext *>(child);
    auto *call = dynamic_cast<SysYParser::CallContext *>(child);
    if (addexp != nullptr){
        debug("start get ret exp");
        auto ret = any_cast<Value *>(visitAddExp(ctx->addExp()));
        debug("get ret exp");
        debug_value(ret);
        return ret;
    }
    else if(call != nullptr)
        return visitCall(ctx->call());
    return (Value *)nullptr;
}

any SysYIRGenerator::visitCond(SysYParser::CondContext *ctx)
{
#ifdef DEBUG
    std::cout << "visitCond" << std::endl;
    cout.flush();
#endif
    auto ret = any_cast<Value *>(visitLOrExp(ctx->lOrExp()));
    return ret;
}

any SysYIRGenerator::visitAddExp(SysYParser::AddExpContext *ctx)
{
#ifdef DEBUG
    std::cout << "visitAddExp" << std::endl;
    cout.flush();
#endif
    auto *child = ctx->children[0];
    auto *Mul = dynamic_cast<SysYParser::MulExpContext *>(child);
    auto *Add = dynamic_cast<SysYParser::AddExpContext *>(child);
    if (Mul)
        return any_cast<Value *>(visitMulExp(ctx->mulExp()));
    else
    {
        auto left = visitAddExp(ctx->addExp());
        auto right = visitMulExp(ctx->mulExp());
        if (ctx->Add()){
            auto ret = (Value *)(builder.createAddInst(any_cast<Value *>(left), any_cast<Value *>(right)));
            // debug("get lala");
            return ret;
        }
        else
            return (Value *)(builder.createSubInst(any_cast<Value *>(left), any_cast<Value *>(right)));
    }
}
// cty 4.23

any SysYIRGenerator::visitRelExp(SysYParser::RelExpContext *ctx)
{
#ifdef DEBUG
    std::cout << "visitRelExp" << std::endl;
    cout.flush();
#endif
    auto *child = ctx->children[0];
    auto *Add = dynamic_cast<SysYParser::AddExpContext *>(child);
    auto *Rel = dynamic_cast<SysYParser::RelExpContext *>(child);

    if (Add)
        return any_cast<Value *>(visitAddExp(ctx->addExp()));
    else
    {
        auto left = visitRelExp(ctx->relExp());
        auto right = visitAddExp(ctx->addExp()); // 只写了int
        // debug("get Rel Exp start");
        if (ctx->Less())
            return (Value *)(builder.createICmpLTInst(any_cast<Value *>(left), any_cast<Value *>(right)));
        else if (ctx->More())
            return (Value *)(builder.createICmpGTInst(any_cast<Value *>(left), any_cast<Value *>(right)));
        else if (ctx->LessEqual())
            return (Value *)(builder.createICmpLEInst(any_cast<Value *>(left), any_cast<Value *>(right)));
        else if (ctx->MoreEqual())
            return (Value *)(builder.createICmpGEInst(any_cast<Value *>(left), any_cast<Value *>(right)));
    }
}

/*-------------yxt-----------------*/

// any SysYIRGenerator::visitNumber(SysYParser::NumberContext *ctx){
//   auto name = any_cast<int> (ctx->IntConst()->getText());//得到number的字符串
//   return ConstantValue::get(name);
// }

/*lAndExp: eqExp | lAndExp And eqExp;*/
any SysYIRGenerator::visitLAndExp(SysYParser::LAndExpContext *ctx)
{
#ifdef DEBUG
    std::cout << "visitLAndExp" << std::endl;
    cout.flush();
#endif
    auto *child = ctx->children[0];
    auto *Eq = dynamic_cast<SysYParser::EqExpContext *>(child);
    auto *Land = dynamic_cast<SysYParser::LAndExpContext *>(child);

    if (Land == nullptr)
    {
        return any_cast<Value *>(visitEqExp(ctx->eqExp()));
    }
    else
    {
        auto *leq = any_cast<Value *>(visitEqExp(ctx->eqExp()));
        auto *rand = any_cast<Value *>(visitLAndExp(ctx->lAndExp()));
        return (Value *)(builder.createLAndInst(leq, rand));
    }
}
/*lOrExp: lAndExp | lOrExp Or lAndExp;*/
any SysYIRGenerator::visitLOrExp(SysYParser::LOrExpContext *ctx)
{
#ifdef DEBUG
    std::cout << "visitLorExp" << std::endl;
    cout.flush();
#endif
    auto *child = ctx->children[0];
    auto *Land = dynamic_cast<SysYParser::LAndExpContext *>(child);
    auto *Lor = dynamic_cast<SysYParser::LOrExpContext *>(child);
    if (Lor == nullptr)
    {
        return any_cast<Value *>(visitLAndExp(ctx->lAndExp()));
    }
    else
    {
        auto left = visitLOrExp(ctx->lOrExp());
        auto right = visitLAndExp(ctx->lAndExp());
        // 自己定义的creatLOrInst指令，在IRBuild.h里面
        return (Value *)(builder.createLOrInst(any_cast<Value *>(left), any_cast<Value *>(right)));
    }
}

any SysYIRGenerator::visitConstExp(SysYParser::ConstExpContext *ctx)
{
#ifdef DEBUG
    std::cout << "visitConstExp" << std::endl;
    cout.flush();
#endif
    return any_cast<Value *>(visitAddExp(ctx->addExp()));
}
/*-------------yxt-----------------*/
// any SysYIRGenerator::visitReturnStmt(SysYParser::ReturnStmtContext *ctx) {
//   auto value =
//       ctx->exp() ? any_cast<Value *>(ctx->exp()->accept(this)) : (Value*)nullptr;
// }

// namespace sysy

/*
any_cast是取出容器中的值
push_back是把数据加入%list的最后
*/

/*
any SysYIRGenerator::visitFunc(SysYParser::FuncContext *ctx) {
    auto name = ctx->ID()->getText();
    auto params = ctx->funcFParams()->funcFParam();
    vector<Type *> paramTypes;
    vector<string> paramNames;
    for (auto param : params) {
    paramTypes.push_back(any_cast<Type *>(visitBtype(param->btype())));
    paramNames.push_back(param->ID()->getText());
    }
    Type *returnType = any_cast<Type *>(visitFuncType(ctx->funcType()));
    auto funcType = Type::getFunctionType(returnType, paramTypes);
    auto function = module->createFunction(name, funcType);
    auto entry = function->getEntryBlock();
    for (auto i = 0; i < paramTypes.size(); ++i)
    entry->createArgument(paramTypes[i], paramNames[i]);
    builder.setPosition(entry, entry->end());
    visitBlockStmt(ctx->blockStmt());
    return function;
}
any SysYIRGenerator::visitBtype(SysYParser::BtypeContext *ctx) {
    return ctx->INT() ? Type::getIntType() : Type::getFloatType();
}

any SysYIRGenerator::visitBlockStmt(SysYParser::BlockStmtContext *ctx) {
    for (auto item : ctx->blockItem()) //是容器，所以要遍历
    visitBlockItem(item);
    return builder.getBasicBlock();
}

any SysYIRGenerator::visitBlockItem(SysYParser::BlockItemContext *ctx) {
    return ctx->decl() ? visitDecl(ctx->decl()) : visitStmt(ctx->stmt());
}

any SysYIRGenerator::visitDecl(SysYParser::DeclContext *ctx) {
    std::vector<Value *> values;
    auto type = any_cast<Type *>(visitBtype(ctx->btype()));
    for (auto varDef : ctx->varDef()) {
    auto name = varDef->lValue()->ID()->getText();
    vector<Value *> dims;
    for (auto exp : varDef->lValue()->exp())
      dims.push_back(any_cast<Value *>(exp->accept(this)));
    auto init = varDef->ASSIGN()
                    ? any_cast<Value *>(visitInitValue(varDef->initValue()))
                    : nullptr;
    values.push_back(module->createGlobalValue(name, type, dims, init));
  }
  // FIXME const
  return values;
}

any SysYIRGenerator::visitLocalDecl(SysYParser::DeclContext *ctx) {
  // a single declaration statement can declare several variables,
  // collect them in a vector
  std::vector<Value *> values;
  // obtain the declared type
  auto type = Type::getPointerType(any_cast<Type *>(visitBtype(ctx->btype())));
  // handle variables
  for (auto varDef : ctx->varDef()) {
    // obtain the variable name and allocate space on the stack
    auto name = varDef->lValue()->ID()->getText();
    auto alloca = builder.createAllocaInst(type, {}, name);
    // update the symbol table
    compUnit->symbols.insert(name, alloca);
    // if an initial value is given, create a store instruction
    if (varDef->ASSIGN()) {
        auto value = any_cast<Value *>(varDef->initValue()->accept(this));
        auto store = builder.createStoreInst(value, alloca);
    }
    // collect the created variable (pointer)
    values.push_back(alloca);
    }
    return values;
}
*/
/*-------------yxt-----------------*/
// 有关stmt语句部分

any SysYIRGenerator::visitStmt(SysYParser::StmtContext *ctx)
{
#ifdef DEBUG
    std::cout << "visitStmt" << std::endl;
    cout.flush();
#endif
    if (ctx->assignStmt())
    {
        // debug("\tStmt start visit");
        auto ret = any_cast<Value *>(visitAssignStmt(ctx->assignStmt()));
        // debug("Stmt get visit");
        return ret;
    }

    if (ctx->expStmt())
    {
        return any_cast<Value *>(visitExpStmt(ctx->expStmt()));
    }

    if (ctx->ifStmt())
    {
        debug("\tStmt start visit If");
        auto ret = any_cast<Value *>(visitIfStmt(ctx->ifStmt()));
        debug("\tStmt get visit If");
        return ret;
    }

    if (ctx->whileStmt())
    {
        return any_cast<Value *>(visitWhileStmt(ctx->whileStmt()));
    }

    if (ctx->breakStmt())
    {
        return any_cast<Value *>(visitBreakStmt(ctx->breakStmt()));
    }

    if (ctx->continueStmt())
    {
        return any_cast<Value *>(visitContinueStmt(ctx->continueStmt()));
    }

    if (ctx->returnStmt())
    {
        return any_cast<Value *>(visitReturnStmt(ctx->returnStmt()));
    }

    if (ctx->block())
    {
        return any_cast<Value *>(visitBlock(ctx->block()));
    }
}

any SysYIRGenerator::visitIfStmt(SysYParser::IfStmtContext *ctx)
{
#ifdef DEBUG
    std::cout << "visitIfStmt" << std::endl;
    cout.flush();
#endif
    // 得到条件表达式
    debug("\t\tget cond start");
    auto cond = any_cast<Value *>(visitCond(ctx->cond()));
    debug("\t\tget cond finished");
    // 得到当前的基本块，builder是一个全局变量，在产生block的语句时会生成基本块
    auto block = builder.getBasicBlock();
    // 得到所属的function
    auto func = block->getParent();
    // 把then和else基本块插入function中
    auto thenblock = func->addBasicBlock();
    auto elseblock = func->addBasicBlock();
    // if-else语句后继基本块
    auto exitblock = func->addBasicBlock();
    // 创建跳转语句，最后两个{}是传参数为空，不写SSA就写{}
    Value *retInst = builder.createCondBrInst(cond, thenblock, elseblock, {}, {});
    // 连接基本块的前驱和后继
    block->getSuccessors().push_back(thenblock);
    thenblock->getPredecessors().push_back(block);
    // set thenblck
    // 设置指令插入在基本块的位置，在then的基本块插入
    builder.setPosition(thenblock, thenblock->end());
    // 访问if后的stmt
    visitStmt(ctx->stmt()[0]);
    // 回到block插入点（此时thenblok已经插入完成）
    builder.setPosition(block, block->end());
    // set elseblock
    block->getSuccessors().push_back(elseblock);
    elseblock->getPredecessors().push_back(block);
    builder.setPosition(elseblock, elseblock->end());
    if (ctx->Else() != nullptr)
    {
        visitStmt(ctx->stmt()[1]);
    }
    else
    { // 如果没有else语句就直接无条件跳转到exitblock
        builder.createUncondBrInst(exitblock, {});
    }
    builder.setPosition(block, block->end());
    // set exitblock
    block->getSuccessors().push_back(exitblock);
    exitblock->getPredecessors().push_back(block);
    // 为后续语句插入设置插入点
    builder.setPosition(exitblock, exitblock->end());
    return retInst;
}

any SysYIRGenerator::visitWhileStmt(SysYParser::WhileStmtContext *ctx)
{
#ifdef DEBUG
    std::cout << "visitWhileStmt" << std::endl;
    cout.flush();
#endif
    // 得到当前的基本块，builder是一个全局变量，在产生block的语句时会生成基本块
    auto block = builder.getBasicBlock();
    // 得到所属的function
    auto func = block->getParent();
    auto entryblock = func->addBasicBlock();
    // 把do基本块插入function
    auto do_block = func->addBasicBlock();
    // 把while语句后继基本块插入function
    auto exitblock = func->addBasicBlock();

    // 得到条件表达式
    builder.setPosition(entryblock, entryblock->end());
    auto cond = any_cast<Value *>(visitCond(ctx->cond()));
    Value *retInst = builder.createCondBrInst(cond, do_block, exitblock, {}, {});
    // 连接基本块的前驱和后继
    // block->getSuccessors().push_back(do_block);
    block->getSuccessors().push_back(entryblock);
    entryblock->getPredecessors().push_back(block);
	entryblock->getPredecessors().push_back(do_block);
	entryblock->getSuccessors().push_back(do_block);
	entryblock->getSuccessors().push_back(exitblock);
    do_block->getPredecessors().push_back(entryblock);
    do_block->getSuccessors().push_back(entryblock);
    exitblock->getPredecessors().push_back(entryblock);
    // do_block->getPredecessors().push_back(block);
    // set do_block
    // 设置指令插入在基本块的位置，do的基本块插入
    builder.setPosition(do_block, do_block->end());
    // 将起始和结束block加入循环栈
    circle.pushStartBlock(entryblock);
    circle.pushExitBlock(exitblock);
    debug("finished circle stack push");
    // 访问while后的stmt
    visitStmt(ctx->stmt());
    builder.createUncondBrInst(entryblock, {});
    // 跳出循环，随即退出循环栈
    circle.popExitBlock();
    circle.popStartBlock();
    // 创建无条件跳转指令到while的cond的基本块
    // 把插入点设置回block
    // builder.setPosition(block, block->end());
    // set exitblock
    // block->getSuccessors().push_back(exitblock);
    // exitblock->getPredecessors().push_back(block);
    
    // 为后续语句插入设置插入点
    builder.setPosition(exitblock, exitblock->end());
    debug("finished circle stack pop");
    return retInst;
}

any SysYIRGenerator::visitAssignStmt(SysYParser::AssignStmtContext *ctx)
{
#ifdef DEBUG
    std::cout << "visitAssignStmt" << std::endl;
    cout.flush();
#endif
    // 得到右边表达式的值
    // debug("get rhs start");
    auto rhs = any_cast<Value *>(visitExp(ctx->exp()));
    // debug("get rhs finished");
    // 得到左边变量的名字
    auto lValue = ctx->lVal();
    auto name = lValue->Ident()->getText();
    auto pointer = compUnit->symbols.lookup(name);
    if (not pointer) // 如果符号表中未找到，输出未定义变量
        perror("undefined variable!");
    debug("assign: ");
    debug_value(pointer);
    Value *store = builder.createStoreInst(rhs, pointer);
    return store;
}

any SysYIRGenerator::visitReturnStmt(SysYParser::ReturnStmtContext *ctx)
{
#ifdef DEBUG
    std::cout << "visitReturnStmt" << std::endl;
    cout.flush();
#endif
    // get the result of exp
    auto value =
        ctx->exp() ? any_cast<Value *>(visitExp(ctx->exp())) : (Value *)nullptr;
    // creat the returnInst
    Value *result = builder.createReturnInst(value);
    return value;
}

any SysYIRGenerator::visitCall(SysYParser::CallContext *ctx)
{
#ifdef DEBUG
    std::cout << "visitCall" << std::endl;
    cout.flush();
#endif
    auto funcName = ctx->Ident()->getText();
    // 可能有问题，没看懂yncast<Function>
    auto func = dynamic_cast<Function *>(compUnit->symbols.lookup(funcName));

    assert(func);
    vector<Value *> args;
    // 如果函数的实参存在
    if (auto rArgs = ctx->funcRParams())
    {
        // 把每个实参（rArgs->exp()中）加入args
        for (auto exp : rArgs->exp())
        {
            args.push_back(any_cast<Value *>(exp->accept(this)));
        }
        Value *call = builder.createCallInst(func, args);
        return call;
    }
}

}
// namespace sysy
